local skynet     = require "skynet"
local socket     = require "skynet.socket"
local netpack    = require "skynet.netpack"
local cjson      = require "cjson"
local datacenter = require "skynet.datacenter"
local config     = require "config"
local msgpack    = require "msgpack"
local mc         = require "skynet.multicast"


math.randomseed(tostring(os.time()):reverse():sub(1, 7))

require "functions"

local WATCHDOG
local gate
local CMD = {}
local uid
local client_fd
local runfork = true
local idletime
local lastgctime

local funcs={}

local handlers = {
    "game.cmd.game",
}

local function send_package(pack)

    if not client_fd then
        return
    end

    local data = pack.data
    data.errcode = data.errcode or 0
    if data and data.errcode and data.errcode>0 and not data.errmsg then
        data.errmsg = config.get("errmsg",string.format("e%d",data.errcode))
    end
    skynet.error("<=========== agent发送消息:",cjson.encode(pack))
    socket.write(client_fd,netpack.pack(msgpack.encode(pack)))
end


local registerHandler = function ()
    for _, v in ipairs(handlers) do
        local handler = require(v)
        if handler then
            for k, func in pairs(handler) do
                if type(func) == 'function' and not string.startwith(k, "_") then
                    local splits = string.split(v, ".")
                    local funname = string.format("on_%s_%s", splits[#splits], k)
                    -- skynet.error("============funname",funname)
                    funcs[funname] = func
                end
            end
        end
    end
end

skynet.register_protocol {
    name = "client",
    id = skynet.PTYPE_CLIENT,
    unpack = function (msg, sz)
        local a= skynet.tostring(msg,sz)
        -- return funpack(a)
        return a
    end,
    dispatch = function (fd, _, msg)
        skynet.ignoreret()
        -- skynet.error("agent收到消息===>",msg)
        local ok,cmd = pcall(msgpack.decode, msg)
        skynet.error("agent recv new msg ===>", cjson.encode(cmd))
        if ok then
            idletime = os.time()

            local c = cmd.c
            local m = cmd.m

            local fname = string.format("on_%s_%s",tostring(c),tostring(m))

            local f  = funcs[fname]
            if f then
                cmd.data.agent = skynet.self()
                local result = f(cmd)
                if result then
                    send_package(result)
                end
            end
        end
    end
}

local function login()
    runfork = true
    -- send_package({ c = "game", m = "login", data = { errcode = 0, data = { id = UID } } })
end


local function autokick()
    skynet.fork(function()
        while runfork do
            if os.time() - idletime > 60 then
                pcall(skynet.send,WATCHDOG,"lua","close",client_fd)
                break
            end
            skynet.sleep(15*100)
        end
    end)
end

function CMD.start(conf)

    skynet.error("agent start conf = ", cjson.encode(conf))

    local fd   = conf.client
    gate       = conf.gate
    WATCHDOG   = conf.watchdog
    client_fd  = fd
    CLIENT_FD  = client_fd

    UID = conf.id
    ROOMID = conf.roomid

    skynet.error("server agent forward fd = ", fd)
    skynet.call(gate, "lua", "forward", fd)
    registerHandler()

    login()
    local ok = pcall(skynet.call, "roommgr",'lua','join', skynet.self(), ROOMID, UID)
    idletime = os.time()
    --是否开启心跳检查
    autokick()
    return "ok"
end

--重连
function CMD.reconnect(fd)
    skynet.error("agent reconnect------>")
    client_fd  = fd
    CLIENT_FD  = client_fd
    skynet.error("server agent forward")
    skynet.call(gate, "lua", "forward", fd)
    login()
    idletime = os.time()
    autokick()
    return "ok"
end

local function logout()
    skynet.error("logout ")
    if SERVICE then
        local ok = pcall(skynet.call, SERVICE,"lua","leave",UID)
        SERVICE = nil
    end
end


function CMD.disconnect()
    skynet.error("disconnect close------>")
    runfork=false
    if SERVICE then
        local ok = pcall(skynet.call,SERVICE,"lua","offline",UID)
    end
    skynet.call(WATCHDOG, "lua", "close", client_fd)
    return "ok"
end


function CMD.exit()
    skynet.error("agent exit------->")
    runfork=false
    logout()
    skynet.exit()
    return 'ok'
end


function CMD.nativesend(cmd)
    -- skynet.error('nativesend--------->', cjson.encode(cmd))

    local c = cmd.c
    local m = cmd.m

    if c=="game" and m=="join" then
        local service = cmd.data.service
        SERVICE = service
        cmd.data.service=nil
        send_package(cmd)
    else
        send_package(cmd)
    end

    return "ok"
end


skynet.start(function()

    skynet.dispatch("lua", function(_,_, command, ...)
        -- skynet.trace()
        --skynet.error("game agent command = ", command)
        local f = CMD[command]

        local ret = f(...)

        if ret then
            skynet.ret(skynet.pack(ret))
        end
    end)
end)
